#include "dirOpt.h"

//初始化一下
int init_session(ClientSession *session, const char *root) {

    // 安全初始化结构体
    memset(session, 0, sizeof(ClientSession));

    // 处理根目录,这里可能要创建基于客户名的单独文件夹，先暂时这样写，到时候可以在安全根目录上再mkdir
    if (!root){
        root = NET_SAVE_ROOT;
    }

    // 直接复制根目录
    strncpy(session->root_dir, root, sizeof(session->root_dir));

    // 确保以'/'结尾
    size_t len = strlen(session->root_dir);
    if (len > 0 && session->root_dir[len-1] != '/') {
        if (len < MAX_PATH_LEN - 1) {
            strncat(session->root_dir, "/", 2);
        }
    }

    // 设置当前目录
    strncpy(session->current_dir,"/",2);

    session->pcn = NULL;
    session->stack_top = 0;
    session->netfd = -1;
    session->opt = 0;

    return 0;
}


int handle_path(ClientSession* css){

    //暂只处理cd 单字符命令进家目录
    if((strcmp(&css->recv_path[0],"~") == 0 || strcmp(&css->recv_path[0],"/")== 0) && strlen(css->recv_path)==1) {
        css->pcn = NULL;
        css->stack_top = 0;
        strncpy(css->current_dir,"/",2);
        return 0;
    }

    // 分割路径组件
    char *saveptr;
    char *token = strtok_r(css->recv_path, "/", &saveptr);

    while (token != NULL) {

        if (strcmp(token, ".") == 0) {
            // 忽略当前目录
        }
        else if (strcmp(token, "..") == 0) {
            // 回退上级目录
            if(css->stack_top == 0){
                token = strtok_r(NULL, "/", &saveptr);
                continue;
            }
            else{
                css->pcn = css->pcn->next;
                css->stack_top --;
            }
        }
        else {
            // 添加新组件
            PathComponent * pcn_tmp = (PathComponent *)calloc(1,sizeof(PathComponent));
            strncpy(pcn_tmp->name,token,sizeof(pcn_tmp->name));
            pcn_tmp->next = css->pcn;
            css->stack_top ++;
            css->pcn = pcn_tmp;

        }
        token = strtok_r(NULL, "/", &saveptr);
    }

    if(css->stack_top == 0){
        strncpy(css->current_dir,"/",2);
    }

    return 0;
}

//弹已经优化好的栈组成路径
int build_path(ClientSession *css){

    PathComponent *pcn = css->pcn;
    char buf[MAX_PATH_LEN] = {0};

    while(pcn!=NULL){
        if(strcmp(&css->current_dir[0],"/")==0){
            css->current_dir[0] = '\0';
        }

        char buf_tmp[MAX_PATH_LEN+64] = {0};
        sprintf(buf_tmp,"%s/%s",pcn->name,buf);
        strncpy(buf,buf_tmp,sizeof(buf));
        pcn = pcn->next;
    }

    memset(css->current_dir,0,sizeof(css->current_dir));
    strncpy(css->current_dir,"/",2);
    strncat(css->current_dir,buf,sizeof(css->current_dir));

    return 0;
}

int sum_path(ClientSession *css){

    char bufs[MAX_PATH_LEN];
    char bufc[MAX_PATH_LEN];
    strncpy(bufs,css->root_dir,sizeof(bufs));
    strncpy(bufc,css->current_dir,sizeof(bufs));

    if(bufs[strlen(bufs)-1] == '/'&&bufc[0] == '/'){
        bufs[strlen(bufs)-1] = '\0';
    }

    bzero(css->sumPath,sizeof(css->sumPath));
    strncat(css->sumPath,bufs,sizeof(css->sumPath));
    strncat(css->sumPath,bufc,sizeof(css->sumPath));

    return 0;
}


//辅助函数，验证绝对路径的真实性，存在的话会返回1
int is_path_accessible(ClientSession *css){

    handle_path(css);
    build_path(css);
    sum_path(css);

    // 检查路径是否存在
    if (access(css->sumPath, F_OK) != 0){
        printf("the path no exist\n");
        return false;
    }
    // 检查访问权限
    if (access(css->sumPath, R_OK | X_OK) != 0){
        printf("the path cant access\n");
        return false;
    }

    // 如果是目录路径，确保是目录
    struct stat path_stat;
    if (stat(css->sumPath, &path_stat)){
        printf("the path no dir\n");
        return false;
    }

    return S_ISDIR(path_stat.st_mode);
}


int check_dir(ClientSession *css){

    char savecur[MAX_PATH_LEN] = {0};

    strncpy(savecur,css->current_dir,strlen(css->current_dir)+1);

    if(!is_path_accessible(css)){
        
        bzero(css->recv_path,sizeof(css->recv_path));
        strncpy(css->recv_path,savecur,strlen(savecur)+1);
        bzero(css->current_dir,sizeof(css->current_dir));
        strncpy(css->current_dir,"/",2);
        css->pcn = NULL;
        css->stack_top = 0;
        handle_path(css);
        build_path(css);
        sum_path(css);
        css->opt = 0;
        return -1;
    }

    if(css->opt == 1){
        bzero(css->recv_path,sizeof(css->recv_path));
        strncpy(css->recv_path,savecur,strlen(savecur)+1);
        css->pcn = NULL;
        css->stack_top = 0;
        char savesum[MAX_PATH_LEN] = {0};
        strncpy(savesum,css->sumPath,strlen(css->sumPath)+1);
        bzero(css->current_dir,sizeof(css->current_dir));
        strncpy(css->current_dir,"/",2);
        handle_path(css);
        build_path(css);
        strncpy(css->sumPath,savesum,strlen(savesum)+1);                                     
        css->opt = 0;

    }

    /* printf("check_dir success\n"); */

    return 0;

}

int cd_dir(ClientSession * css){

    if(check_dir(css) == -1) return -1;

    char buf[MAX_PATH_LEN] = {0};

    if(strlen(css->current_dir)>1&&css->current_dir[strlen(css->current_dir)-1] == '/'){
        strncpy(buf,css->current_dir,strlen(css->current_dir)-1);
    }
    if(strlen(buf)<=1) buf[0] = '/';

    printf("cd success:%s\n",buf);
    send(css->netfd,buf,strlen(buf),0);

    return 0;
}

int ls_dir(ClientSession *css){

    css->opt = 1;
    if(check_dir(css) == -1) return -1;

    DIR *dir = opendir(css->sumPath);

    if (!dir) {
        fprintf(stderr, "Cannot open directory: %s\n", css->sumPath);
        return -1;
    }

    char dirList[MAX_LS_BUFFER] = {0};
    struct dirent *entry;

    while ((entry = readdir(dir)) != NULL) {
        char buf[512] = {0};

        // 跳过隐藏文件
        if (entry->d_name[0] == '.') continue;

        // 获取文件类型标记
        char type = ' ';

        if (entry->d_type == DT_DIR) {
            type = '/';
        } else if (entry->d_type == DT_LNK) {
            type = '@';
        } else if (entry->d_type == DT_FIFO) {
            type = '|';
        } else if (entry->d_type == DT_SOCK) {
            type = '=';
        }

        sprintf(buf,"%s%c\t",entry->d_name,type);
        strcat(dirList,buf);
    }

    closedir(dir);
    printf("ls success:%s\n",dirList);
    send(css->netfd,dirList,strlen(dirList)+1,0);

    return 0;
}


int pwd_dir(ClientSession *css){

    char pwdBuf[MAX_PATH_LEN] = {0};

    //笨方法，确保即将输出的pwd内容以'/'开头,并无'/'结尾                                            
    if(css->current_dir[0] != '/'){
        pwdBuf[0] = '/';
        strncat(pwdBuf,css->current_dir,sizeof(pwdBuf)-1);
    }
    else{
        strncpy(pwdBuf,css->current_dir,sizeof(pwdBuf));
    }
    if(pwdBuf[strlen(pwdBuf)-1] == '/'&&strlen(pwdBuf)>1) pwdBuf[strlen(pwdBuf)-1] = '\0';

    printf("pwd_dir success: %s\n",pwdBuf);
    send(css->netfd,pwdBuf,strlen(pwdBuf)+1,0);

    return 0;
}

int mk_dir(ClientSession *css){

    char recvTmp[MAX_PATH_LEN] = {0};
    strncpy(recvTmp,css->recv_path,sizeof(recvTmp));
    char *last_slash = strrchr(css->recv_path, '/'); // 查找最后一个'/'的位置

    char lastname[1024] = {0};
    if (last_slash != NULL) {
        strncpy(lastname,last_slash+1,strlen(last_slash+1));
        *last_slash = '\0'; // 截断字符串（保留最后一个'/'之前的内容）
    }else{
        if(strlen(css->recv_path)>1){
            bzero(css->recv_path,sizeof(css->recv_path));
            strncpy(lastname,recvTmp,strlen(recvTmp)+1);
        }
    }

    css->opt = 1;
    if(check_dir(css) == -1) return -1;

    char target[MAX_PATH_LEN] = {0};

    strncat(target,css->sumPath,strlen(css->sumPath)+1);
    strncat(target,lastname,strlen(lastname)+1);


    // 移除结尾的斜杠（mkdir需要）
    size_t len = strlen(target);
    if (len > 0 && target[len-1] == '/') {
        target[len-1] = '\0';
    }

    // 检查目录是否已存在
    if (access(target, F_OK) == 0) {
        fprintf(stderr, "Directory already exists: %s\n", target);
        return false;
    }

    // 创建目录（权限：用户读写执行）
    if (mkdir(target, 0700)) {                                                       
        perror("mkdir failed");
        return false;
    }

    printf("make success\n");
    send(css->netfd,"mksuccess",9,0);

    return 0;
}

int rm_dir(ClientSession * css){

    css->opt = 1;
    if(check_dir(css) == -1) return -1;

    char target[MAX_PATH_LEN] = {0};
    strncpy(target,css->sumPath,sizeof(target));

    // 移除结尾的斜杠（rmdir需要）
    size_t len = strlen(target);
    if (len > 0 && target[len-1] == '/') {
        target[len-1] = '\0';
    }

    // 检查目录是否存在
    if (access(target, F_OK) != 0) {
        fprintf(stderr, "Directory does not exist: %s\n", target);
        return false;
    }

    // 检查是否为目录
    struct stat path_stat;
    if (stat(target, &path_stat) || !S_ISDIR(path_stat.st_mode)) {
        fprintf(stderr, "Not a directory: %s\n", target);
        return false;
    }

    // 删除空目录
    if (rmdir(target)) {
        perror("rmdir failed");
        return false;
    }


    printf("remove success!\n");
    send(css->netfd,"rmsuccess",9,0);

    return 0;
}

int opt_dir(ClientSession *css,int opt,char *recv_path){                                 

    bzero(css->recv_path,sizeof(css->recv_path));
    strncpy(css->recv_path,recv_path,strlen(recv_path));

    if(opt == 1){
        cd_dir(css);
    }else if (opt == 2){
        ls_dir(css);
    }else if (opt == 3){
        pwd_dir(css);
    }else if (opt ==4){
        mk_dir(css);
    }else if(opt == 5){
        rm_dir(css);
    }else{
        printf("error option num!\n");
        return -1;
    }
    printf("finish topname:%s\n——————————————\n",css->pcn->name);

    return 0;
}

